#include "command.h"
#include <i_component_factory.h>
#include <i_string.h>
#include <i_component_container.h>
#include <string>
#include <iostream>

CCommand::CCommand()
{

}

CCommand::~CCommand()
{

}

signal<const CCommandInfoPtr&>& CCommand::GetCommandSignal(const std::string& cmd)
{
	return m_signals[cmd];
}

void CCommand::PostCommand(const CCommandInfoPtr& cmd)
{
	GetContainer()->PostComponent(getComID(), [cmd](const CComponentPtr& ptr) -> void {
		CCommand* self = dynamic_cast<CCommand*>(ptr.get());
		if (self == nullptr)
			return;

		self->GetCommandSignal(cmd->cmd)(cmd);
	});
}

int CCommand::_OnStart()
{
	m_worker = std::thread(&CCommand::_Svc, this);
	return 0;
}

void CCommand::_OnStop()
{
	if (m_worker.joinable())
		m_worker.detach();
}

inline bool IsValidCharactor(char ch)
{
	return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' && ch >= '0' && ch <= '9';
}

CCommandInfoPtr CCommand::_Parse(std::string& input)
{
	input = TrimString(input);
	if (input.empty())
		return CCommandInfoPtr();
	
	std::vector<std::string> str_vec = SplitString(input);
	CCommandInfoPtr ptr = std::make_shared<CCommandInfo>();
	ptr->cmd = str_vec[0];
	bool is_quote = false;
	for (size_t n = 1; n < str_vec.size(); ++n)
	{
		std::string& str = str_vec[n];
		if (is_quote)
		{
			if (str.empty())
				ptr->params.back().append(" ");
			else
			{
				ptr->params.back().append(str);
				if (str.back() == '"')
				{
					is_quote = false;
					ptr->params.back().pop_back();
				}
			}
		}
		else
		{
			char first = *str.begin();
			if (first == '-')
			{
				// option
				static const std::string EQ = "=";
				auto kv = SplitString(str, EQ);
				std::string& key = kv[0];
				if(key.length() == 1)
					continue;

				std::string& value = ptr->options[key.substr(1, key.length() - 1)];
				if (kv.size() >= 2)
					value = kv[1];
			}
			else
			{
				ptr->params.resize(ptr->params.size() + 1);
				if (first == '"')
				{
					is_quote = true;
					ptr->params.back().append(str, 1);
				}
				else
					ptr->params.back() = str;
				
			}
		}
	}

	return ptr;
}

void CCommand::_Svc()
{
	while (GetStatus() != ECOMPONENT_STATUS_STOPPING)
	{
		std::string user_input;
		std::getline(std::cin, user_input);
		auto ptr = _Parse(user_input);
		if (ptr)
			PostCommand(ptr);
	}
}

DEFINE_COMPONENT(COM_DEF<CCommand, ICommand>);
